StockDiscussion.tsx 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. 'use client';
  2. // D2 종목 토론 탭 — 통계 헤더 + 글 목록(DefaultListLayout 스타일) + 글쓰기(로그인 게이트).
  3. // 목록은 SSR 로 받은 initial 데이터를 렌더하고, 페이징은 링크로 처리(?tab=discussion&page=).
  4. import '@/app/styles/community.scss';
  5. import Link from 'next/link';
  6. import { useState } from 'react';
  7. import { useMemberContext } from '@/contexts/memberProvider';
  8. import { formatDate } from '@/lib/utils/client';
  9. import { StockBoardPostsResponse } from '@/types/community';
  10. import StockWriteForm from './StockWriteForm';
  11. interface Props {
  12. code: string;
  13. stockName?: string|null;
  14. page: number;
  15. perPage: number;
  16. data: StockBoardPostsResponse;
  17. }
  18. export default function StockDiscussion({ code, stockName, page, perPage, data }: Props)
  19. {
  20. const { member } = useMemberContext();
  21. const [writing, setWriting] = useState(false);
  22. const stats = data.stats;
  23. const list = data.list;
  24. const startIndex = data.total - (page - 1) * perPage;
  25. const totalPages = Math.max(Math.ceil(data.total / perPage), 1);
  26. return (
  27. <div className='stock-discussion'>
  28. <div className='stock-discussion__stats'>
  29. <span>전체 글<strong>{stats.posts.toLocaleString()}</strong></span>
  30. <span>댓글<strong>{stats.comments.toLocaleString()}</strong></span>
  31. {stats.lastPostAt && <span>최근 작성<strong>{formatDate(stats.lastPostAt)}</strong></span>}
  32. </div>
  33. <div className='stock-discussion__head'>
  34. <span className='stock-discussion__count'>총 {data.total.toLocaleString()}건</span>
  35. {member ? (
  36. !writing && (
  37. <button type='button' className='stock-write-toggle' onClick={() => setWriting(true)}>
  38. 글쓰기
  39. </button>
  40. )
  41. ) : null}
  42. </div>
  43. {member && writing && (
  44. <StockWriteForm stockCode={code} stockName={stockName} onDone={() => setWriting(false)} />
  45. )}
  46. {!member && (
  47. <div className='stock-write-login'>
  48. <Link href='/login'>로그인</Link> 후 토론에 참여할 수 있습니다.
  49. </div>
  50. )}
  51. {list.length === 0 ? (
  52. <p className='stock-discussion__empty'>등록된 글이 없습니다. 첫 글을 남겨보세요.</p>
  53. ) : (
  54. <table className='stock-discussion__table'>
  55. <caption className='sr-only'>{stockName ?? code} 토론 글 목록 — 번호·제목·작성자·작성일·조회·좋아요</caption>
  56. <thead>
  57. <tr>
  58. <th className='stock-discussion__col--num-h' scope='col'>번호</th>
  59. <th scope='col'>제목</th>
  60. <th className='stock-discussion__col--author' scope='col'>작성자</th>
  61. <th scope='col'>작성일</th>
  62. <th className='stock-discussion__col--views' scope='col'>조회</th>
  63. <th scope='col'>추천</th>
  64. </tr>
  65. </thead>
  66. <tbody>
  67. {list.map((row, i) => (
  68. <tr key={row.id}>
  69. <td className='stock-discussion__table-num'>{startIndex - i}</td>
  70. <td>
  71. <Link href={`/post/${row.id}`} className='stock-discussion__subject'>
  72. {row.hasPrediction && <span className='prediction-tag prediction-tag--flat' title='예측 글'>예측</span>}
  73. <em>{row.subject}</em>
  74. {row.comments > 0 && <span className='stock-discussion__comments'>[{row.comments}]</span>}
  75. </Link>
  76. </td>
  77. <td className='stock-discussion__col--author'>{row.name || row.sid || '익명'}</td>
  78. <td className='stock-discussion__table-meta'>{formatDate(row.createdAt)}</td>
  79. <td className='stock-discussion__col--views stock-discussion__table-meta'>{row.views.toLocaleString()}</td>
  80. <td className='stock-discussion__table-meta'>{row.likes.toLocaleString()}</td>
  81. </tr>
  82. ))}
  83. </tbody>
  84. </table>
  85. )}
  86. {data.total > perPage && (
  87. <nav className='track-leaderboard__actions' aria-label='페이지'>
  88. {page > 1 && (
  89. <Link href={`/stock/${code}?tab=discussion&page=${page - 1}`} className='track-leaderboard__btn'>이전</Link>
  90. )}
  91. <span className='stock-discussion__count'>{page} / {totalPages}</span>
  92. {page < totalPages && (
  93. <Link href={`/stock/${code}?tab=discussion&page=${page + 1}`} className='track-leaderboard__btn'>다음</Link>
  94. )}
  95. </nav>
  96. )}
  97. </div>
  98. );
  99. }